/*
 *jquery.contentcarousel是一个能够制作出无限循环展示的jQuery内容滑块插件。
 *这个内容滑块插件的下方还有一个“more”内容块，点击它可以调出更详细的文字说明。
 * http://www.htmleaf.com/jQuery/Slideshow-Scroller/20141105392.html
 */

(function ($) {
    var aux = {
        // navigates left / right
        navigate: function (dir, $el, $wrapper, opts, cache) {

            var scroll = opts.scroll,
                    factor = 1,
                    idxClicked = 0;
            if (cache.expanded) {
                scroll = 1; // scroll is always 1 in full mode
                factor = 3; // the width of the expanded item will be 3 times bigger than 1 collapsed item
                idxClicked = cache.idxClicked; // the index of the clicked item
            }

            // clone the elements on the right / left and append / prepend them according to dir and scroll
            if (dir === 1) {
                $wrapper.find('div.ca-item:lt(' + scroll + ')').each(function (i) {
                    $(this).clone(true).css('left', (cache.totalItems - idxClicked + i) * cache.itemW * factor + 'px').appendTo($wrapper);
                });
            } else {
                var $first = $wrapper.children().eq(0);
                $wrapper.find('div.ca-item:gt(' + (cache.totalItems - 1 - scroll) + ')').each(function (i) {
                    // insert before $first so they stay in the right order
                    $(this).clone(true).css('left', -(scroll - i + idxClicked) * cache.itemW * factor + 'px').insertBefore($first);
                });
            }

            // animate the left of each item
            // the calculations are dependent on dir and on the cache.expanded value
            $wrapper.find('div.ca-item').each(function (i) {
                var $item = $(this);
                $item.stop().animate({
                    left: (dir === 1) ? '-=' + (cache.itemW * factor * scroll) + 'px' : '+=' + (cache.itemW * factor * scroll) + 'px'
                }, opts.sliderSpeed, opts.sliderEasing, function () {
                    if ((dir === 1 && $item.position().left < -idxClicked * cache.itemW * factor) || (dir === -1 && $item.position().left > ((cache.totalItems - 1 - idxClicked) * cache.itemW * factor))) {
                        // remove the item that was cloned
                        $item.remove();
                    }
                    cache.isAnimating = false;
                });
            });
        },
        // opens an item (animation) -> opens all the others
        openItem: function ($wrapper, $item, opts, cache) {
            cache.idxClicked = $item.index();
            // the item's position (1, 2, or 3) on the viewport (the visible items)
            cache.winpos = aux.getWinPos($item.position().left, cache);
            $wrapper.find('div.ca-item').not($item).hide();
            $item.find('div.ca-content-wrapper').css('left', cache.itemW + 'px').stop().animate({
                width: cache.itemW * 2 + 'px',
                left: cache.itemW + 'px'
            }, opts.itemSpeed, opts.itemEasing)
                    .end()
                    .stop()
                    .animate({
                        left: '0px'
                    }, opts.itemSpeed, opts.itemEasing, function () {
                        cache.isAnimating = false;
                        cache.expanded = true;
                        aux.openItems($wrapper, $item, opts, cache);
                    });
        },
        // opens all the items
        openItems: function ($wrapper, $openedItem, opts, cache) {
            var openedIdx = $openedItem.index();
            $wrapper.find('div.ca-item').each(function (i) {
                var $item = $(this),
                        idx = $item.index();
                if (idx !== openedIdx) {
                    $item.css('left', -(openedIdx - idx) * (cache.itemW * 3) + 'px').show().find('div.ca-content-wrapper').css({
                        left: cache.itemW + 'px',
                        width: cache.itemW * 2 + 'px'
                    });
                    // hide more link
                    aux.toggleMore($item, false);
                }
            });
        },
        // show / hide the item's more button
        toggleMore: function ($item, show) {
            (show) ? $item.find('a.ca-more').show() : $item.find('a.ca-more').hide();
        },
        // close all the items
        // the current one is animated
        closeItems: function ($wrapper, $openedItem, opts, cache) {
            var openedIdx = $openedItem.index();
            $openedItem.find('div.ca-content-wrapper').stop().animate({
                width: '0px'
            }, opts.itemSpeed, opts.itemEasing)
                    .end()
                    .stop()
                    .animate({
                        left: cache.itemW * (cache.winpos - 1) + 'px'
                    }, opts.itemSpeed, opts.itemEasing, function () {
                        cache.isAnimating = false;
                        cache.expanded = false;
                    });
            // show more link
            aux.toggleMore($openedItem, true);
            $wrapper.find('div.ca-item').each(function (i) {
                var $item = $(this),
                        idx = $item.index();
                if (idx !== openedIdx) {
                    $item.find('div.ca-content-wrapper').css({
                        width: '0px'
                    })
                            .end()
                            .css('left', ((cache.winpos - 1) - (openedIdx - idx)) * cache.itemW + 'px')
                            .show();
                    // show more link
                    aux.toggleMore($item, true);
                }
            });
        },
        // gets the item's position (1, 2, or 3) on the viewport (the visible items)
        // val is the left of the item
        getWinPos: function (val, cache) {
            switch (val) {
                case 0 					:
                    return 1;
                    break;
                case cache.itemW 		:
                    return 2;
                    break;
                case cache.itemW * 2 	:
                    return 3;
                    break;
            }
        }
    },
            methods = {
                init: function (options) {

                    if (this.length) {

                        var settings = {
                            sliderSpeed: 500, // speed for the sliding animation
                            sliderEasing: 'easeOutExpo', // easing for the sliding animation
                            itemSpeed: 500, // speed for the item animation (open / close)
                            itemEasing: 'easeOutExpo', // easing for the item animation (open / close)
                            scroll: 1				// number of items to scroll at a time
                        };
                        return this.each(function () {

                            // if options exist, lets merge them with our default settings
                            if (options) {
                                $.extend(settings, options);
                            }

                            var $el = $(this),
                                    $wrapper = $el.find('div.ca-wrapper'),
                                    $items = $wrapper.children('div.ca-item'),
                                    cache = {};
                            // save the with of one item
                            cache.itemW = $items.width();
                            // save the number of total items
                            cache.totalItems = $items.length;
                            // add navigation buttons
                            if (cache.totalItems > 3)
                                $el.prepend('<div class="ca-nav"><span class="ca-nav-prev">Previous</span><span class="ca-nav-next">Next</span></div>')

                            // control the scroll value
                            if (settings.scroll < 1)
                                settings.scroll = 1;
                            else if (settings.scroll > 3)
                                settings.scroll = 3;
                            var $navPrev = $el.find('span.ca-nav-prev'),
                                    $navNext = $el.find('span.ca-nav-next');
                            // hide the items except the first 3
                            $wrapper.css('overflow', 'hidden');
                            // the items will have position absolute
                            // calculate the left of each item
                            $items.each(function (i) {
                                $(this).css({
                                    position: 'absolute',
                                    left: i * cache.itemW + 'px'
                                });
                            });
                            // click to open the item(s)
                            $el.find('a.ca-more').live('click.contentcarousel', function (event) {
                                if (cache.isAnimating)
                                    return false;
                                cache.isAnimating = true;
                                $(this).hide();
                                var $item = $(this).closest('div.ca-item');
                                aux.openItem($wrapper, $item, settings, cache);
                                return false;
                            });
                            // click to close the item(s)
                            $el.find('a.ca-close').live('click.contentcarousel', function (event) {
                                if (cache.isAnimating)
                                    return false;
                                cache.isAnimating = true;
                                var $item = $(this).closest('div.ca-item');
                                aux.closeItems($wrapper, $item, settings, cache);
                                return false;
                            });
                            // navigate left
                            $navPrev.bind('click.contentcarousel', function (event) {
                                if (cache.isAnimating)
                                    return false;
                                cache.isAnimating = true;
                                aux.navigate(-1, $el, $wrapper, settings, cache);
                            });
                            // navigate right
                            $navNext.bind('click.contentcarousel', function (event) {
                                if (cache.isAnimating)
                                    return false;
                                cache.isAnimating = true;
                                aux.navigate(1, $el, $wrapper, settings, cache);
                            });
                            // adds events to the mouse
                            $el.bind('mousewheel.contentcarousel', function (e, delta) {
                                if (delta > 0) {
                                    if (cache.isAnimating)
                                        return false;
                                    cache.isAnimating = true;
                                    aux.navigate(-1, $el, $wrapper, settings, cache);
                                } else {
                                    if (cache.isAnimating)
                                        return false;
                                    cache.isAnimating = true;
                                    aux.navigate(1, $el, $wrapper, settings, cache);
                                }
                                return false;
                            });
                        });
                    }
                }
            };
    $.fn.contentcarousel = function (method) {
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method ' + method + ' does not exist on jQuery.contentcarousel');
        }
    };
})(jQuery);